<template>
    <form @submit.prevent="handleSubmit">
        <slot></slot>
    </form>
</template>

<script setup lang="ts">
import { onMounted, reactive, provide } from 'vue';
// 定义规则类型
export type RuleItem = {
    trigger: "Input" | "Change" | "Blur";
    type: "Required" | "Numbric",
    errorMsg: string,
    name: string,
}
// 定义FormModel接口
interface Record{
    [key: string]: unknown;
}
// 定义子组件InputComponent的接口
interface InputComponent {
    validate(trigger: string): boolean;
}
// 定义组件属性
const props = defineProps<{
    rules: RuleItem[];
    modelValue?: Record;
}>();
// 定义事件
const emit = defineEmits<{
    'update:modelValue': [value: Record];
    'submit': [formData: Record, isValid: boolean];
}>();
// 存储表单内的所有Input组件引用
const inputComponents = reactive<Map<string, InputComponent>>(new Map());
// 存储校验状态
const validationStatus = reactive<Record>({});
// 注册子组件
const registerInput = (name: string, component: InputComponent) => {
    inputComponents.set(name, component);
};
// 处理子组件的校验结果
const handleValidation = (name: string, isValid: boolean, errorMsg: string) => {
    validationStatus[name] = { valid: isValid, errorMsg };
}
// 校验整个表单
const validateForm = (): boolean => {
    let isValid = true;
    // 对每个注册的Input组件进行校验
    inputComponents.forEach((component, name) => {
        // 找到该输入框对应的规则
        const inputRules = props.rules.filter(rule => rule.name === name);

        // 找出所有需要的触发器
        const triggers = new Set<string>();
        inputRules.forEach(rule => triggers.add(rule.trigger));

        // 对每个触发器执行校验
        triggers.forEach(trigger => {
            const result = component.validate(trigger);
            if (!result) isValid = false;
        });
    });
    return isValid;
}
// 处理表单提交
const handleSubmit = () => {
    const isVaild = validateForm();
    emit('submit', props.modelValue || {}, isVaild);
}
const resetValidation = () => {
    inputComponents.forEach((component)=>{
        component.validate('Reset');
    });
    Object.keys(validationStatus).forEach(key => {
        validationStatus[key] = {
            valid: true,
            errorMsg: ''
        }
    })
}
// 暴露方法给父组件
defineExpose({
    validate: validateForm,
    registerInput,
    handleValidation,
    resetValidation
})
// 提供给子组件使用的方法和状态
provide('formContext', {
    registerInput,
    handleValidation,
    rules: props.rules
})
onMounted(() => {
    // 组件挂载后可以执行一些初始化操作
})
</script>

<style scoped lang="css">
.error-msg {
    color: #f56c6c;
    font-size: 12px;
    line-height: 1;
    padding-top: 4px;
}
</style>